/**
 * gislin 2017年9月19日
 */
package com.btcode.orm.model.generater;

import com.btcode.db.executer.IDataExecuter;
import com.btcode.db.fieldtype.FieldType;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * @author gislin 2017年9月19日
 */
public abstract class ModelGenerater {

    protected IDataExecuter executer;

    public ModelGenerater(IDataExecuter executer) {
        this.executer = executer;
    }

    public void generaterFile(String packName, String tableName, String dir) throws IOException {

        File folder = new File(dir);
        boolean mkdirResult = folder.mkdirs();

        if(!mkdirResult){
            System.out.println("创建目录失败："+dir);
        }

        String modelName = getModelName(tableName);
        Writer modelFileWriter = null;
        try{

            modelFileWriter = new BufferedWriter(
                new OutputStreamWriter(
                    new FileOutputStream(dir + "/" + modelName + ".java"), "UTF-8"));

            String text = generater(packName, tableName);
            text = text.replaceAll("\t", "    ");
            modelFileWriter.write(text);
        }
        finally {
            if(modelFileWriter!=null){
                try{
                    modelFileWriter.flush();
                    modelFileWriter.close();
                }catch (Exception e){
                    throw e;
                }
            }
        }
    }

    public abstract List<TableInfoModel> getTableInfoModels(String tableName);

    public String generater(String packName, String tableName) {

        List<TableInfoModel> tableInfoModels = getTableInfoModels(tableName);

        StringBuffer strBuffer = new StringBuffer();
        String modelName = getModelName(tableName);

        strBuffer.append("package " + packName + ";\r\n");

        appendImport(strBuffer, tableInfoModels);

        strBuffer.append("@SuppressWarnings(\"unchecked\")\r\n");
        strBuffer.append("public class " + modelName + " extends BaseModel {\r\n");

        appendSerialVersionUID(strBuffer);
        appendTableNameField(strBuffer, tableName);
        appendColumnField(strBuffer, tableInfoModels, modelName);
        //		appendConstructor(strBuffer, tableInfoModels, modelName);
        appendGetterSetter(strBuffer, tableInfoModels, modelName);
        appendGetTableMethod(strBuffer);
        appendIsNeedCacheMethod(strBuffer, tableName);

        strBuffer.append("}");

        return strBuffer.toString();
    }

    private void appendImport(StringBuffer strBuffer, List<TableInfoModel> tableInfoModels) {
        strBuffer.append("\r\n");

        Set<String> fileTypeSet = new HashSet<String>();

        for (TableInfoModel column : tableInfoModels) {
            String dataType = column.getDataType();
            String fileType = getFieldJavaType(dataType);
            fileTypeSet.add(fileType);
        }

        for (String fileType : fileTypeSet) {
            if (fileType.equals("Date")) {
                strBuffer.append("import java.util.Date" + ";\r\n");
            }
        }

        strBuffer.append("import com.btcode.db.fieldtype.FieldType" + ";\r\n");
        strBuffer.append("import com.btcode.orm.model.BaseModel" + ";\r\n");
        strBuffer.append("import com.btcode.orm.model.Field" + ";\r\n");
        strBuffer.append("import com.btcode.orm.model.IField" + ";\r\n");
        strBuffer.append("\r\n");
    }

    private void appendTableNameField(StringBuffer strBuffer, String tableName) {
        strBuffer.append("\r\n");
        strBuffer.append("\tpublic static String tableName = \"" + tableName + "\";\r\n");
        strBuffer.append("\r\n");
    }

    private void appendSerialVersionUID(StringBuffer strBuffer) {
        strBuffer.append("\r\n");
        strBuffer.append("\tprivate static final long serialVersionUID = 1L;\r\n");
        strBuffer.append("\r\n");
    }

    private void appendColumnField(StringBuffer strBuffer, List<TableInfoModel> tableInfoModels,
        String modelName) {
        strBuffer.append("\r\n");
        for (TableInfoModel column : tableInfoModels) {
            String columnName = column.getColumnName();
            String fileType = getFieldEmunType(column.getDataType()).toString();
            String fieldName = getFieldName(columnName);
            String isKey = "false";
            String isUnique = "false";

            if (column.getIsKey() != null && column.getIsKey().trim().toLowerCase().equals(
                "true")) {
                isKey = "true";
            }

            if (column.getIsUnique() != null && column.getIsUnique().trim().toLowerCase().equals(
                "true")) {
                isUnique = "true";
            }

            strBuffer.append(
                "\tpublic static IField " + fieldName + " = new Field(" + modelName + ".class,\""
                    + columnName + "\",FieldType." + fileType + "," + isKey + ",true," + isUnique
                    + ");\r\n");
            strBuffer.append("\r\n");
        }
    }

    @SuppressWarnings("unused")
    private void appendConstructor(StringBuffer strBuffer, List<TableInfoModel> tableInfoModels,
        String modelName) {
        strBuffer.append("\tpublic " + modelName + "(){\r\n");
        strBuffer.append("\r\n");

        for (TableInfoModel column : tableInfoModels) {
            String columnName = column.getColumnName();
            String fieldName = getFieldName(columnName);
            strBuffer.append("\t\taddField(" + fieldName + ");\r\n");
        }

        strBuffer.append("\r\n");
        strBuffer.append("\t }\r\n");
    }

    private void appendGetterSetter(StringBuffer strBuffer, List<TableInfoModel> tableInfoModels,
        String modelName) {

        for (TableInfoModel column : tableInfoModels) {

            String columnName = column.getColumnName();
            String fileName = getFieldName(columnName);
            String dataType = column.getDataType();
            String fileType = getFieldJavaType(dataType);

            String setMethodName = getSetterMethodName(columnName);
            String getMethodName = getGetterMethodName(columnName);

            strBuffer.append("\tpublic void " + setMethodName + "(" + fileType + " value){\r\n");
            strBuffer.append(
                "\t\tsetFieldValue(" + modelName + "." + fileName + ".getFieldName(), value);\r\n");
            strBuffer.append("\t}\r\n");

            strBuffer.append("\r\n");

            strBuffer.append("\tpublic " + fileType + " " + getMethodName + "(){\r\n");
            strBuffer.append("\t\tObject value = getFieldValue(" + modelName + "." + fileName
                                 + ".getFieldName());\r\n");
            strBuffer.append("\t\treturn getValueConver().converTo" + fileType + "(value);\r\n");
            strBuffer.append("\t}\r\n");

            strBuffer.append("\r\n");
        }

    }

    private void appendGetTableMethod(StringBuffer strBuffer) {
        strBuffer.append("\r\n");
        strBuffer.append("\tpublic String getTableName() {\r\n");
        strBuffer.append("\t\treturn tableName;\r\n");
        strBuffer.append("\t}\r\n");
        strBuffer.append("\r\n");
    }

    private void appendIsNeedCacheMethod(StringBuffer strBuffer, String tableName) {
        strBuffer.append("\r\n");
        strBuffer.append("\tpublic boolean isNeedCache() {\r\n");
        strBuffer.append("\t\treturn false;\r\n");
        strBuffer.append("\t}\r\n");
        strBuffer.append("\r\n");
    }

    public String getModelName(String tableName) {

        String[] infos = tableName.split("_");

        StringBuffer modelNameBuf = new StringBuffer();

        for (String info : infos) {
            modelNameBuf.append(info.substring(0, 1).toUpperCase() + info.substring(1).toLowerCase());
        }

        modelNameBuf.append("Model");

        return modelNameBuf.toString();
    }

    private String getFieldName(String columnName) {

        String[] infos = columnName.split("_");

        StringBuffer fieldNameBuf = new StringBuffer();

        for (int i = 0; i < infos.length; i++) {
            String info = infos[i];
            if (i == 0) {
                fieldNameBuf.append(info.substring(0, 1).toLowerCase() + info.substring(1).toLowerCase());
            }
            else {
                fieldNameBuf.append(info.substring(0, 1).toUpperCase() + info.substring(1).toLowerCase());
            }
        }

        return fieldNameBuf.toString();
    }

    private String getGetterMethodName(String columnName) {
        String fieldName = getFieldName(columnName);
        fieldName = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
        return fieldName;
    }

    private String getSetterMethodName(String columnName) {
        String fieldName = getFieldName(columnName);
        fieldName = "set" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
        return fieldName;
    }

    public abstract FieldType getFieldEmunType(String type);

    public abstract String getFieldJavaType(String type);
}
